#!/usr/bin/env python
#
# Sanity-test torrent-server upload/download/delete code
#

import commands
import glob
import httplib
import logging
import optparse
import os
from pipes import quote
import random
import sys
import urllib
from urlparse import urlparse

def upload(path, options):
    args = {
        "--email" : options.email,
        "--password" : options.password,
        "--url" : options.url
        }
    arguments = "--info " + " ".join([ key+"="+value for key,value in args.iteritems() ])
    shell_command = " ".join([options.path, arguments, quote(path)])
    (status, hash) = commands.getstatusoutput(shell_command)
    if status != 0:
        print("ERROR: Command %s returned status %d (%s)"%(shell_command, status, hash))
        sys.exit(1)
    return hash # Note: getstatusoutput strips trailing newline for us

def verify(path, infohash, options):
    if os.path.isdir(path):
        for root, dirs, files in os.walk(path):
            for f in files:
                if f.startswith("."): continue   # Ignore .files
                full_path = os.path.join(root, f)
                verify(full_path, infohash, options)
            for d in dirs:
                if d.startswith("."): dirs.remove(d)  # Ignore .directories
    else:
        url = urlparse(options.url, "http", False)  # Returns 6-tuple: scheme://netloc/path;parameters?query#fragment
        host = url[1]
        filesize = os.path.getsize(path)
        fp = open(path, "rb")
        if filesize < 1024:  # Less than 1K: fetch the whole thing.
            expected = fp.read()
            conn = httplib.HTTPConnection(host)
            conn.request("GET", "/seed/%s/%s"%(infohash, urllib.quote(path)))
            response = conn.getresponse()
            actual = response.read()
            conn.close()
            if actual != expected:
                print("ERROR "+path)
                print("Expecting: "+repr(expected))
                print(" got: "+repr(actual))
                sys.exit(1)
            # Fetch again using /seed/hoffman:
            if filesize > 0:
                conn = httplib.HTTPConnection(host)
                raw_hash = urllib.quote(infohash.decode('hex_codec'))
                conn.request("GET", "/seed/hoffman?info_hash=%s&piece=0"%raw_hash)
                response = conn.getresponse()
                actual = response.read()
                conn.close()
                if actual != expected:
                    print("ERROR hoffman-fetching "+path)
                    print("Expecting: "+repr(expected))
                    print(" got: "+repr(actual))
                    sys.exit(1)
            
        else: # Big:  Pick an arbitrary 1K piece to check:
            start = random.randint(0, filesize-1024)
            fp.seek(start)
            expected = fp.read(1024)
            conn = httplib.HTTPConnection(host)
            headers = { "Range" : "bytes=%d-%d"%(start,start+1023) }
            conn.request("GET", "/seed/%s/%s"%(infohash, urllib.quote(path)), None, headers)
            response = conn.getresponse()
            actual = response.read()
            conn.close()
            if actual != expected:
                print("ERROR %s, bytes %d-%d"%(path, start, start+1023))
                print("Expecting: "+repr(expected))
                print(" got: "+repr(actual))
                sys.exit(1)
            
        fp.close()

def delete(hash, options):
    args = {
        "--email" : options.email,
        "--password" : options.password,
        "--url" : options.url
        }
    arguments = "--delete " + " ".join([ key+"="+value for key,value in args.iteritems() ])
    shell_command = " ".join([options.path, arguments, quote(hash)])
    (status, output) = commands.getstatusoutput(shell_command)
    if status != 0:
        print("ERROR: Command %s returned status %d (%s)"%(shell_command, status, output))
        sys.exit(1)

def main():
    parser = optparse.OptionParser(usage="%prog [options] file_or_directory_or_.torrent")
    parser.add_option("--url", dest="url", default="http://localhost:8080/remote_api",
                  help="URL for app engine application (default: %default)")
    parser.add_option("-e", "--email", dest="email", default="arbitrary@e.mail",
                  help="Username to use. (default: %default)")
    parser.add_option("--password", dest="password", default="foo",
                  help="Password to use.  (default: %default)")
    parser.add_option("-p", "--path", dest="path", default="../torrent-server/upload_torrent.py",
                  help="Path to upload script (default: %default)")
    (options, args) = parser.parse_args()
    
    path_hashes = {}
    test_stuff = glob.glob("*")
    print("Uploading:")
    for path in test_stuff:
        print(" "+path)
        path_hashes[path] = upload(path, options)

    shared = "2_MB_ZeroesOnes"
    shared_hash = path_hashes[shared]
    print("Testing reference counting: deleting "+shared)
    delete(shared_hash, options)
    del path_hashes[shared]

    print("Verifying:")
    for (path, hash) in path_hashes.iteritems():
        print(" "+path)
        verify(path, hash, options)

    print("Cleaning up: deleting")
    for (path, hash) in path_hashes.iteritems():
        print(" "+path)
        delete(hash, options)


if __name__ == '__main__':
    logging.basicConfig(level=logging.WARNING)
    main()
